package goo

import (
	"log"
	"sort"
	"strings"
	"sync"
)

var routes *Routes
var onceRoute sync.Once
var routeAddLock sync.Mutex

type RoutesInterface interface {
	Controller()
}

type Routes struct {
	_Interceptor3
	routeFunc               map[string]func(*Context)
	routePattern            []string
	prefix                  string                         //Add方法时的前缀
	pattern                 string                         //当前添加的路由,用来添加拦截器
	controllerInterceptor   []func(invocation *Invocation) //controller方法内添加的拦截器方法
	inControllerMethod      bool                           //是否在controller方法内添加路由或拦截器
	controllerMethodPattern []string                       //controller方法内添加的路由
}

func RoutesInstance() *Routes {
	onceRoute.Do(func() {
		routes = &Routes{routeFunc: make(map[string]func(*Context)), routePattern: make([]string, 0),
			controllerInterceptor: make([]func(invocation *Invocation), 0),
			inControllerMethod:    false}
	})
	return routes
}

func (routes *Routes) Any(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.Get(pattern, handle)
	routes.Post(pattern, handle)
	routes.Put(pattern, handle)
	routes.Delete(pattern, handle)
	routes.Options(pattern, handle)
	routes.Head(pattern, handle)
	routes.Trace(pattern, handle)
	routes.Patch(pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Get(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("GET", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Post(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("POST", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Put(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("PUT", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Delete(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("DELETE", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Head(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("HEAD", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Options(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("OPTIONS", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Trace(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("TRACE", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) Patch(pattern string, handle func(*Context)) *_Interceptor2 {
	routes.addRoute("PATCH", pattern, handle)
	return InterceptorInstance()._interceptor2
}

func (routes *Routes) addRoute(method string, pattern string, handle func(*Context)) {
	pattern = method + ":" + fmtRoutePattern(RoutesInstance().prefix+fmtPattern(pattern))
	RoutesInstance().routeFunc[pattern] = handle
	RoutesInstance().routePattern = append(RoutesInstance().routePattern, pattern)
	RoutesInstance().pattern = pattern
	InterceptorInstance().AddInterceptor(pattern, RoutesInstance().controllerInterceptor)
	if RoutesInstance().inControllerMethod {
		RoutesInstance().controllerMethodPattern = append(RoutesInstance().controllerMethodPattern, pattern)
	}
	log.Printf("add route %s ==> %s\n", pattern, "func(*Content){...}")
}

func (routes *Routes) Add(pattern string, routesImpl RoutesInterface) *_Interceptor {
	routeAddLock.Lock()
	RoutesInstance().controllerInterceptor = make([]func(invocation *Invocation), 0)
	RoutesInstance().controllerMethodPattern = make([]string, 0)
	RoutesInstance().prefix = fmtPattern(pattern)
	RoutesInstance().inControllerMethod = true
	routesImpl.Controller()
	RoutesInstance().inControllerMethod = false
	RoutesInstance().prefix = ""
	RoutesInstance().controllerInterceptor = make([]func(invocation *Invocation), 0)
	routeAddLock.Unlock()
	return InterceptorInstance()._interceptor
}

func (routes *Routes) sort() {
	sort.SliceStable(RoutesInstance().routePattern, func(i, j int) bool {
		l1 := strings.Count(RoutesInstance().routePattern[i], "/")
		l2 := strings.Count(RoutesInstance().routePattern[j], "/")
		if l1 == l2 {
			l1 = len(RoutesInstance().routePattern[i])
			l2 = len(RoutesInstance().routePattern[j])
		}
		return l1 > l2
	})
}

//处理前缀后缀,约定 前缀一定有"/",后缀一定没"/"
func fmtPattern(pattern string) string {
	return "/" + strings.Trim(pattern, "/")
}

//处理..或.
func fmtRoutePattern(pattern string) string {
	pts := strings.Split(pattern[1:], "/")
	pt := make([]string, 0)
	for _, p := range pts {
		if ".." == p {
			if len(pt) > 0 {
				pt = pt[:len(pt)-1]
			}
		} else if "." == p {
		} else {
			pt = append(pt, p)
		}
	}
	pattern = ""
	for _, ps := range pt {
		pattern = pattern + "/" + ps
	}
	return pattern
}
